Spring cloud Sleuth and Zipkin

Sleuth 主要用于日志采样,而 Zipkin 用于实现服务链路追踪,他们分别是微服务中最为常用的项目之一,其中 Zipkin 可以实现数据存储(支持 ES、MySQL、cASSANDRA)以及简单部署和文档完善等优势深受开发者喜爱。

Sleuth 由 Spring cloud 团队借助 Google Dapper、Twitter Zipkin、Apache Htrace 进行设计。而 Zipkin 还有一个 OpenZipkin 项目,是 Zipkin 的完全开源版本,项目由 2021年起源与 Twitter,同样基于 Google Dapper 论文进行实现。

Dapper,一种大规模分布式系统跟踪基础设施
https://research.google/pubs/pub36356/

首先,我们需要来介绍下服务链路追踪的作用,现在很多文章一开始就跟你巴拉巴拉 Zipkin、HTrace 原理什么的,他们的基本概念就是监控微服务状态,及时发现并定位问题的点,并快速解决问题。

对于服务链路追踪,主要的就是实现监控为服务系统,来提供及时且准确的性能报告,并统计请求所耗费的时间以及具体网络延迟情况并辅助开发/运维人员分析并解决系统所存在的问题。

其实最为主要的还是通过他来快速定位故障,这也是解决问题最主要的原因 ——发现问题,通过服务链路追踪可以定位问题的故障点,并采取措施来解决问题,并提供快速检测或预警,隔离和修复问题等方式。

Google Dapper

Google Dapper 是一个在 2010 年 5 月由 Benjaim H. Sigelman, Luiz Andr’e Burrows, Pat Stephenson, Manoj Plakal, Donald Beaver, Saul jasper, Chandan shanbhag 发布于谷歌技术报告中的一篇关于大规模分布式系统跟踪的一篇论文。

他奠定了之后的 Sleuth 以及 Zipkin 的开发与实施,都提供了前期的架构和一种概念,起初 Dapper 是一个自包含的跟踪工具,后来发展为一个监控平台。

跨度 (Span)

跨度(Span)这是一个在 Dapper 中的一个基本工作单位,发送一个 RPC 请求,就是一个新的 Span,其中还包含了其他数据,例如描述、时间戳时间、注释这些。

从上图中,客户端(前端请求)所调用的服务单元,这个过程就是一次 Span ,发起请求的客户端或前端请求的 Span id:1 ,而下一个请求的 Span id:2 ……

他们都是一个父集关系因此 Span 还有一个 parent id 也就是父集 ID,父集的 ID 为 no parent id 也被称之为 root parent,那么 Span id:2 的服务自然为parent id:1

跟踪 (Trace)

之后为了将 Span 记录的更加完整,也就是最终形成一个完整的树状结构,那么也会有一个 trace id,他的主要作用就是将 Span 标注为一个组中,在可视化界面中更加的好理解。

标注 (Annotation)

用于记录事件的存在,可以定义请求的开始和停止等信息,例如客户端发送了一个请求,Annotation 会描述的开始、服务器端获得、准本开始处理:

Id Name Info
1 cs, Client Sent 客户端发送,客户端发送了请求
2 sr,Server Received 服务端收到了请求并开始处理(根据时间戳可以从 cs ~ sr 这段时间减时间戳获取网络延迟)
3 ss,Server Sent 服务器发送,在请求处理完成时进行标注(Annotation),这个时间戳减去 sr 的时间戳,就可以得到服务器端处理所需要的时间
4 cr,Client Received 客户端收到,表示 Span 结束,客户端已经成够收到了服务器端发送的相应(因此时间戳减去 cs 就是客户端从服务器接受响应所需的全部时间)

Sleuth 日志采样

Sleuth 与 Spring Cloud 高度契合,兼容了 Zipkin、HTrace、Log-based 追踪为服务调用链路,而我们用 Sleuth 主实现的就是返回 Span\Trace id,主要使用到 spring-cloud-starter-sleuth 依赖:

1
2
3
4
5
6
7
8
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

除此之外还有 Spring cloud 全局配置,添加 sleuth 的配置项(在最新版本中无需添加),以及项目的 application.name 等:

1
2
3
4
5
6
7
8
9
spring:
application:
name: SleuthService
sleuth:
sampler:
probability: 0.3 # 设置抽样采集率为 30%,默认为 0.1 即 10%

server:
port: 8210

Application.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
package com.example.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.logging.Logger;


/**
* 实现日志采样(msg echo log?)
*
* @author kunlun
* @date 2021/7/24
*/
@SpringBootApplication
@RestController
public class DemoApplication {

public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}

private static final Logger LOG = Logger.getLogger(DemoApplication.class.getName());

@GetMapping("/hey")
public String hey() {
LOG.info("return /hey view");
return "hello";
}
}

其中 Logger 主要的作用就是将信息输出到控制台上,也就是通过 @GetMapping 进行请求所返回的相关信息,当然你也可以配合服务集群来实现服务消费者的作用。当访问 http://localhost:8210/hey 接口后,控制台输出格式为 [应用名称,Trace id,Span id] 直观点的就是 SleuthService,9d1a88683cbacd11,9d1a88683cbacd11

如果启动后没有关于 Sleuth 相关的信息,那么可以通过 application.yml 全局配置文件中添加日志输出为 DEBUG 类型看看:

1
2
3
logging:
level:
ROOT: DEBUG

Zipkin

Zipkin 同样是基于 Google Dapper 由 Twitter 所开发的且已经被 Spring cloud 良好的集成,你可以理解为他是 Sleuth 的数据可视化版本,并且通过 Annotation 来展示服务的相关信息,但首先你需要下载 Zipkin 的控制台并运行:

1
2
curl -sSL https://zipkin.io/quickstart.sh | bash -s
java -jar zipkin.jar

同时它还支持 Docker、从源代码运行等方式来启动,对于我来说通过 Jar 方式来执行已经非常便捷了,最坏的结果就是你需要先 clone 一下,然后在编译一下,之后在设置为 bin 一下,然后出错了又找一下,简单多了。

启动完后最为主要的是 http://127.0.0.1:9411/ 这也是 Zipkin 的默认端口和地址,记录下来之后在项目中进行绑定并添加依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-consul-discovery</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.cloud/spring-cloud-starter-zipkin -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-zipkin</artifactId>
<version>2.2.8.RELEASE</version>
</dependency>

实际上主要是 spring-cloud-starter-zipkin ,至于其他的只是我测试环境需要用到的,当然 spring-boot-starter-web 是可以不用加的,如果加了的话需要在配置文件中声明 main-web-application-type=reactive 来保证服务的正常启动(Gateway 已经存在了 web)

Application.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
spring:
application:
name: Zipkin
cloud:
gateway:
routes:
- id: hey
uri: lb://service-provider/hey
predicates:
- Path=/hey
discovery:
locator:
# 允许服务发现
enabled: true
consul:
host: localhost
port: 8500
discovery:
service-name: service-provider
zipkin:
base-url: http://localhost:9411
sender:
type: web
main:
web-application-type: reactive
server:
port: 8210

之后请求相应的接口并重新在 Zipkin 控制台上点击 RUN QUERY 刷新下请求列表即可获取当前服务的响应以及依赖关系等更加详细的视图,读者可根据自身需要来进行查阅,但唯一不好的就是 Zipkin 不是异步刷新,需要手动点……,以及在查看详细请求数据的时候界面没有返回按钮(也许设计起初是为了靠浏览器自带的 <- -> 来实现窗口的返回)。

本文使用《江雪分析公开知识存储库知识共享许可证》进行发布